fix(sonarcloud): declare all supported Python versions to Sonar - #92
Conversation
Dependency ReviewThe following issues were found:
License Issues.github/workflows/sonarcloud.yml
OpenSSF Scorecard
Scanned Files
|
There was a problem hiding this comment.
Pull request overview
This PR fixes SonarCloud and SonarLint false positives by declaring the full set of Python versions the source code must support, aligned with requires-python (>=3.11,<3.15), rather than only the single CI build version.
Changes:
- Update
sonar-project.propertiesto setsonar.python.version=3.11,3.12,3.13,3.14for accurate local and IDE (SonarLint) analysis. - Update the SonarCloud reusable workflow pin to a revision that supports the new
sonar-python-versioninput. - Pass
sonar-python-version: '3.11,3.12,3.13,3.14'to SonarCloud while keepingpython-version: '3.12'for CI runtime.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| sonar-project.properties | Aligns sonar.python.version with the project’s supported Python range for correct local and SonarLint analysis. |
| .github/workflows/sonarcloud.yml | Passes the supported Python version range to SonarCloud and updates the reusable workflow pin to a compatible revision. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Team Run ID: 📒 Files selected for processing (1)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. WalkthroughSonarCloud configuration now analyzes Python 3.11 through 3.14. The workflow keeps Python 3.12 as the build version and uses an updated reusable workflow revision. ChangesSonarCloud Python version support
Estimated code review effort: 1 (Trivial) | ~5 minutes Merge Risk: ⚪ Minimal · up to This updates Sonar analysis to cover supported Python versions 3.11 through 3.14 without changing the CI runtime version. No concrete merge-blocking risk remains. Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Full details: Docstring CoverageExplanation No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0 files. (1 skipped: 1 unsupported.) ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/sonarcloud.yml:
- Line 32: Update the python-sonarcloud reusable workflow checkout to disable
credential persistence by configuring its checkout step with persist-credentials
set to false. Alternatively, update the pinned reusable-workflow revision to one
that already applies this setting, while preserving the existing workflow
permissions.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: d04ae5a2-393f-438b-839a-f6b15bc61b4d
📒 Files selected for processing (2)
.github/workflows/sonarcloud.ymlsonar-project.properties
| sonarcloud: | ||
| name: SonarCloud Analysis | ||
| uses: ByronWilliamsCPA/.github/.github/workflows/python-sonarcloud.yml@74c633acfdd5f707ab154fd59bd212c6df663dd6 # main | ||
| uses: ByronWilliamsCPA/.github/.github/workflows/python-sonarcloud.yml@4bd2d7c207a7fcf2dfcec8416c805d06d745c241 # main |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== repository workflow =="
git ls-files .github/workflows/sonarcloud.yml || true
if [ -f .github/workflows/sonarcloud.yml ]; then
nl -ba .github/workflows/sonarcloud.yml | sed -n '1,220p'
fi
echo
echo "== available git references for pinned reusable workflow =="
git ls-remote --heads --tags https://github.com/ByronWilliamsCPA/.github.git 4bd2d7c207a7fcf2dfcec8416c805d06d745c241 || true
git ls-remote https://github.com/ByronWilliamsCPA/.github.git main || true
echo
echo "== raw reusable workflow around checkout and job permissions =="
python3 - <<'PY'
import urllib.request
pinned = "4bd2d7c207a7fcf2dfcec8416c805d06d745c241"
url = f"https://raw.githubusercontent.com/ByronWilliamsCPA/.github/{pinned}/.github/workflows/python-sonarcloud.yml"
try:
with urllib.request.urlopen(url, timeout=20) as r:
data = r.read().decode()
lines = data.splitlines()
for i, line in enumerate(lines, 1):
if "actions/checkout" in line or "permissions:" in line or "pull-requests:" in line or "sonar-python-version" in line:
start=max(1,i-8); end=min(len(lines), i+10)
print(f"--- matches line {i} range {start}-{end} ---")
for j in range(start, end+1):
print(f"{j:4}: {lines[j-1]}")
except Exception as e:
print(f"ERROR fetching {url}: {e.__class__.__name__}: {e}")
PY
echo
echo "== checkout input defaults around persist-credentials =="
python3 - <<'PY'
import urllib.request
base = "https://raw.githubusercontent.com/actions/checkout"
for ref in ["v4", "main", "9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0"]:
try:
url = f"{base}/{ref}/action.yml"
data = urllib.request.urlopen(url, timeout=20).read().decode()
lines = data.splitlines()
print(f"--- action.yml {ref} ---")
for i,line in enumerate(lines,1):
if "persist-credentials" in line:
print(f"{i:4}: {line}")
except Exception as e:
print(f"ERROR for checkout {ref}: {e}")
PYRepository: ByronWilliamsCPA/rag-processor
Length of output: 267
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== check workflow trigger and job contents =="
nl -ba .github/workflows/sonarcloud.yml | sed -n '1,220p'
echo
echo "== resolve exact reusable workflow workflow file by git API =="
git ls-remote https://github.com/ByronWilliamsCPA/.github.git 4bd2d7c207a7fcf2dfcec8416c805d06d745c241 || true
git ls-remote https://github.com/ByronWilliamsCPA/.github.git refs/tags/main || true
git ls-remote https://github.com/ByronWilliamsCPA/.github.git refs/heads/main || trueRepository: ByronWilliamsCPA/rag-processor
Length of output: 254
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== repository workflow =="
awk '{printf "%5d: %s\n", NR, $0}' .github/workflows/sonarcloud.yml | sed -n '1,220p'
echo
echo "== raw reusable workflow around checkout, permissions, and inputs =="
python3 - <<'PY'
import urllib.request
pinned = "4bd2d7c207a7fcf2dfcec8416c805d06d745c241"
url = f"https://raw.githubusercontent.com/ByronWilliamsCPA/.github/{pinned}/.github/workflows/python-sonarcloud.yml"
try:
with urllib.request.urlopen(url, timeout=20) as r:
data = r.read().decode()
except Exception as e:
print(f"ERROR fetching {url}: {e.__class__.__name__}: {e}")
raise SystemExit(1)
lines = data.splitlines()
for i, line in enumerate(lines, 1):
if any(k in line for k in ("actions/checkout", "permissions:", "'pull-requests:', 'pull-requests:", "pull-requests:", "sonar-python-version", "GITHUB_TOKEN", "GITHUB_OUTPUT")):
print(f"--- matches line {i} ---")
for j in range(max(1, i-8), min(len(lines), i+10)+1):
print(f"{j:4}: {lines[j-1]}")
echo
echo "== checkout persist-credentials input description from action.yml =="
python3 - <<'PY'
import urllib.request
base = "https://raw.githubusercontent.com/actions/checkout"
for ref in ["v4"]:
try:
data = urllib.request.urlopen(f"{base}/{ref}/action.yml", timeout=20).read().decode()
print(f"--- {ref} ---")
for i, line in enumerate(data.splitlines(), 1):
if "persist-credentials" in line or line.strip() == "description:":
print(f"{i:4}: {line}")
except Exception as e:
print(f"ERROR checkout {ref}: {e}")
PYRepository: ByronWilliamsCPA/rag-processor
Length of output: 2359
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== raw reusable workflow around sensitive lines =="
python3 - <<'PY'
import urllib.request
pinned = "4bd2d7c207a7fcf2dfcec8416c805d06d745c241"
url = f"https://raw.githubusercontent.com/ByronWilliamsCPA/.github/{pinned}/.github/workflows/python-sonarcloud.yml"
try:
lines = urllib.request.urlopen(url, timeout=20).read().decode().splitlines()
except Exception as e:
print(f"ERROR fetching {url}: {e.__class__.__name__}: {e}")
else:
for i, line in enumerate(lines, 1):
if "actions/checkout" in line or "GITHUB_TOKEN" in line or "pull-requests" in line or "sonar-python-version" in line or "uv sync" in line or "pytest" in line or "GH_TOKEN" in line:
start=max(1,i-10); end=min(len(lines), i+12)
print(f"--- matches line {i} range {start}-{end} ---")
for j in range(start, end+1):
print(f"{j:4}: {lines[j-1]}")
echo
echo "== GitHub action checkout persist-credentials from v4 == "
python3 - <<'PY'
import urllib.request
data = urllib.request.urlopen("https://raw.githubusercontent.com/actions/checkout/v4/action.yml", timeout=20).read().decode()
for i, line in enumerate(data.splitlines(), 1):
if "persist-credentials" in line:
print(f"{i:4}: {line}")
PYRepository: ByronWilliamsCPA/rag-processor
Length of output: 353
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== reusable workflow relevant sections =="
python3 - <<'PY'
import urllib.request
sha = "4bd2d7c207a7fcf2dfcec8416c805d06d745c241"
url = f"https://raw.githubusercontent.com/ByronWilliamsCPA/.github/{sha}/.github/workflows/python-sonarcloud.yml"
try:
text = urllib.request.urlopen(url, timeout=20).read().decode()
except Exception as e:
print(f"ERROR fetching {url}: {e.__class__.__name__}: {e}")
raise SystemExit(1)
lines = text.splitlines()
keywords = ["actions/checkout", "persist-credentials", "GITHUB_TOKEN", "pull-requests", "uv sync", "pytest", "sonar-python-version", "GH_TOKEN"]
for i, line in enumerate(lines, 1):
if any(k in line for k in keywords):
start=max(1,i-10); end=min(len(lines), i+12)
print(f"--- matches line {i} range {start}-{end} ---")
for j in range(start, end+1):
print(f"{j:4}: {lines[j-1]}")
PY
echo
echo "== actions/checkout persist-credentials reference from v4 =="
python3 - <<'PY'
import urllib.request
text = urllib.request.urlopen("https://raw.githubusercontent.com/actions/checkout/v4/action.yml", timeout=20).read().decode()
for i, line in enumerate(text.splitlines(), 1):
if "persist-credentials" in line:
print(f"{i:4}: {line}")
PYRepository: ByronWilliamsCPA/rag-processor
Length of output: 511
🌐 Web query:
GitHub actions checkout v4 persist-credentials default true action.yml
💡 Result:
In the official action.yml configuration for the GitHub Actions checkout action, the default value for the persist-credentials input is true [1][2]. When persist-credentials is set to its default value (true), the authentication token or SSH key used to clone the repository is configured in the local Git configuration. This allows subsequent scripts in your workflow job to run authenticated Git commands [3][4]. The token is automatically removed during the post-job cleanup phase [3][2]. If you wish to opt out of this behavior—for example, to prevent the credential from being stored in the local Git configuration—you can explicitly set persist-credentials to false in your workflow file [3][4]. While there have been community discussions and pull requests proposing to change this default to false for security hardening [5], it remains true in the official v4 and v6 releases of the action [1][6].
Citations:
- 1: https://github.com/actions/checkout/blob/v4/action.yml
- 2: https://github.com/actions/checkout/tree/v4.3.1
- 3: https://github.com/actions/checkout/blob/v4/README.md
- 4: https://github.com/actions/checkout?tab=readme-ov-file
- 5: Change the default value of persist-credentials to false actions/checkout#1687
- 6: https://raw.githubusercontent.com/actions/checkout/v6/action.yml
Sensitive Data Exposure (CWE-522): Insufficiently Protected Credentials
Reachability: Internal
Disable persisted credentials in the reusable workflow checkout.
This job grants pull-requests: write before the pinned reusable workflow checkout persists GITHUB_TOKEN in Git credentials by default. This token remains available until post-job cleanup. Set persist-credentials: false on the checkout step in ByronWilliamsCPA/.github/.github/workflows/python-sonarcloud.yml, or pin a reusable-workflow revision that already disables it.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/sonarcloud.yml at line 32, Update the python-sonarcloud
reusable workflow checkout to disable credential persistence by configuring its
checkout step with persist-credentials set to false. Alternatively, update the
pinned reusable-workflow revision to one that already applies this setting,
while preserving the existing workflow permissions.
Sources: Coding guidelines, Path instructions, Learnings, MCP tools
a5fc0f6 to
d533a29
Compare
sonar.python.version was 3.12, the single version CI builds with, while requires-python is ">=3.11,<3.15". SonarPython gates version-specific rules on ALL declared versions (PythonVersionUtils.areSourcePythonVersionsGreaterOrEqualThan is allMatch), so declaring only 3.12 made every 3.12-gated rule fire against code that must still run on 3.11. That produced 2 live false positives today: S6794 and S6796 urging PEP 695 "type X = ..." aliases, which are a SyntaxError on 3.11. Declaring the full range makes allMatch(>=3.12) false, so the rules correctly stay silent until the floor moves. Sets the new sonar-python-version input (ByronWilliamsCPA/.github#291) and bumps the uses: pin to the commit that introduces it, since the input does not exist in the previously pinned revision and passing an undefined input fails the reusable workflow at startup. Also syncs sonar-project.properties. CI overrides that key via -D, so it does not affect the pipeline, but SonarLint in the IDE reads it and would otherwise keep raising the same false positives locally that CI no longer reports. python-version stays 3.12: it feeds actions/setup-python and is the version the project builds and runs tests with, which is a separate concern from the versions the source must remain compatible with. Pre-commit: all hooks pass except pydoclint, which fails identically on untouched main (DOC105/109/110 in fuzz/*.py). This change touches no Python, so it is scoped out with SKIP=pydoclint rather than bypassed.
d533a29 to
ca394e4
Compare
|



Problem
sonar.python.versionwas3.12, the single version CI builds with, while this project'srequires-pythonis">=3.11,<3.15".SonarPython gates version-specific rules on all declared versions:
PythonVersionUtils.areSourcePythonVersionsGreaterOrEqualThanis anallMatch. Declaringonly
3.12therefore satisfies every>= 3.12gate, so those rules fire against code thatmust still run on 3.11.
This is not theoretical. SonarCloud currently reports 2 open issues in this repo from
python:S6794/python:S6796, both urging PEP 695type X = ...alias syntax. That syntaxis a
SyntaxErroron 3.11, which this project still supports. The rules are correct about3.12; they are wrong about this project.
Fix
Declare the full range so
allMatch(>= 3.12)is false and the 3.12-gated rules correctlystay silent until the floor actually moves:
python-versionstays3.12. It feedsactions/setup-pythonand is the version the projectbuilds and tests with, which is a genuinely separate concern from the versions the source
must remain compatible with. Conflating the two is what caused this.
Why the pin moves too
sonar-python-versionis new in ByronWilliamsCPA/.github#291 and does not exist in thepreviously pinned revision. Passing an input the callee does not declare fails a reusable
workflow at startup, so the pin has to move to the commit that introduces it
(
4bd2d7c, the squash commit of #291 onmain).Also in this change
sonar-project.propertiesis synced to the same list. CI overrides that key via-Dsonar.python.version, so it has no effect on the pipeline, but SonarLint in the IDEreads it and would otherwise keep raising locally the exact false positives CI no longer
reports.
Verification
actionlintrc=0,yamllintcleanpre-commit run --all-files: every hook passes exceptpydoclint, which fails identicallyon untouched
main(DOC105/109/110 infuzz/*.py). This change touches no Python at all,so it is scoped out with
SKIP=pydoclintrather than bypassed with--no-verify.Expected result
The 2 open S6794/S6796 issues should clear on the next analysis. If they do not, the pin or
the input name is wrong and this should be reverted rather than papered over.
Note for maintainers
pydoclintis failing onmainin this repo independently of this PR. Worth a separate fix.Summary by CodeRabbit